#include "netasciiMode.h"

#include <string.h> /*for strlen,strcpy*/
#include <stdlib.h> /*for calloc*/

#include "../logger/logger.h"

//Carringe Return and Line Feed chars
enum CRLF{LF='\n', CR='\r', CARRY=1};

//forward declarations
char* addCR(char* data);
int byteOnBuffer(char* start,char* end);

/**
 * author: Haim Tsolker.
 * 
 * handleAscii
 * 
 * data - msg_p contain UNIX format string
 * 
 * preform manipulate on data that after any apperance of \n
 * putting a \r right after it.
 * #of character that exceeded will be read at next time.
 * putting a flag if \n apper at the end of manipulate data,
 * so that it handle next time
 * return msg_p in windows format. 
 */
msg_p handleAscii(msg_p data)
{
	char fileBuffer[BLOCKSIZE+1];
	char* pawn;
	int actualByteRead=0,actualByteInBuffer=0;
	int counterForCR=0;
	int savedBufferSize=data->size;
	pawn=data->data;
	if(0==data->size)
	{
		return data;
	}
	memset((void*)fileBuffer,0,sizeof(char)*sizeof(fileBuffer));
	memcpy((void*)fileBuffer,(void*)(data->data),sizeof(char)*BLOCKSIZE);
	memset((void*)(data->data),0,sizeof(char)*sizeof(fileBuffer));
	actualByteRead=byteOnBuffer(data->data,pawn)-counterForCR;
	if(NULL!=data->additinalData)
	{
		if(*((int*)data->additinalData) == CARRY)
		{
			*pawn=CR;
			++pawn;
			++actualByteRead;
			*((int*)data->additinalData)=0;
		}
	}
	do
	{
		pawn=(char*)memccpy((void*)pawn,(void*)(fileBuffer+actualByteRead),LF,BLOCKSIZE-(actualByteRead+counterForCR));
		if(pawn)
		{

			++counterForCR;			
			if(pawn == data->data+BLOCKSIZE)
			{
				if(NULL==data->additinalData)
				{
					data->additinalData=calloc(1,sizeof(int));
				}
				*((int*)data->additinalData) = CARRY;
				*(pawn)='\0';
				pawn=NULL;
			}
			else
			{
				addCR(pawn);
				++pawn;
				actualByteRead=byteOnBuffer(data->data,pawn)-counterForCR;
			}
		}
		else
		{
			if(NULL==(pawn=memchr(data->data,EOF,BLOCKSIZE)))
			{
				pawn=data->data+(BLOCKSIZE);
			}
			actualByteInBuffer = byteOnBuffer(data->data,pawn);
			pawn=NULL;
		}
	}while(pawn && (pawn < data->data+BLOCKSIZE));
	data->offset = (data->size+counterForCR) > BLOCKSIZE  ? (data->size+counterForCR-BLOCKSIZE):0;
	if(data->size < BLOCKSIZE)
	{
		data->size = (data->size+counterForCR) > BLOCKSIZE ? BLOCKSIZE:(savedBufferSize+counterForCR);
		if(data->size<BLOCKSIZE && NULL!=data->additinalData)
		{
			free(data->additinalData);
		}
	}
	return data;
}

/**
 * addCR
 * 
 * data - location to place a CR
 * 
 * place a CR at the given location.
 * returned value is the pointer given pointer.
 */
char* addCR(char* data)
{
	*(data)=CR;
	return data;
}

/**
 * byteOnBuffer
 * 
 * start - begining of the string
 * end - end of the string
 * 
 * calculate the number of chars between start and end (as it might contain '\0')
 */
int byteOnBuffer(char* start,char* end)
{
	return (end-start)/sizeof(char);
}
